/*************************************************************************
	> File Name: uart.c
	> Author: yuarmy
	> Mail: yuarmy@126.com 
	> Created Time: Sun 03 Aug 2014 05:26:51 AM PDT
 ************************************************************************/

#include<stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <errno.h>
#include <inttypes.h>
#include <memory.h>
#include <time.h>
#define GPIO_MODE_DIR "/sys/devices/virtual/misc/gpio/mode/"
#define GPIO_PIN_DIR "/sys/devices/virtual/misc/gpio/pin/"
#define MAX_GPIO_NUM 23
#define MAX_GPIO_MODE_NUM 8
#define GPIO0  0 
#define GPIO1  1 
#define IO_UART_FUNC  3
#define GPIO_IF_PREFIX "gpio"

#define UARTNAME "/dev/ttyS1"
typedef struct tagSHDevManage {
  int32_t server_sockfd;
  int32_t client_sockfd;
  int32_t test_sockfd;
  int32_t uart_fd;
  fd_set readfds;
  fd_set writefds;
  struct termios orig_term;
  struct termios uart_term;
  int32_t client_state;
  int32_t uart_state;
}SHDEVMANAGE_T;

SHDEVMANAGE_T shdev_;
int gpio_pin_fd[MAX_GPIO_NUM+1];
int gpio_mode_fd[MAX_GPIO_NUM+1];

int32_t InitGPIO() {
    int i;
     char path[1024];
     for( i = 0; i<= MAX_GPIO_NUM; ++i)
     {
         memset(path, 0, sizeof(path));
         sprintf(path, "%s%s%d", GPIO_PIN_DIR, GPIO_IF_PREFIX, i);
         gpio_pin_fd[i] = open(path, O_RDWR);
         if ( gpio_pin_fd[i] < 0 )
         {
             fprintf(stderr, "open %s failed\n", path);
             return -1;
         }
         
         memset(path, 0, sizeof(path));
         sprintf(path, "%s%s%d", GPIO_MODE_DIR, GPIO_IF_PREFIX, i);
         gpio_mode_fd[i] = open(path, O_RDWR);
         if ( gpio_mode_fd[i] < 0 )
         {
             fprintf(stderr, "open %s failed\n", path);
             return -1;
         } 
     }
 
 return 0;
}
static int write_to_file(int fd, char *str, int len)
{
    int ret = -1;

    lseek(fd, 0, SEEK_SET);
    ret = write(fd, str, len);
    if ( ret <= 0 )
    {
        fprintf(stderr, "write %d failed\n", fd);
        return -1;
    }
    return ret;
}

int32_t hw_pinMode(uint8_t pin, uint8_t mode)
{
    int fd;
     char buf[4];
     int ret = -1;
    
     if ( (pin >= 0 && pin <=  MAX_GPIO_NUM) && (mode <= MAX_GPIO_MODE_NUM) )
     {
         memset((void *)buf, 0, sizeof(buf));
         sprintf(buf, "%d", mode);
         ret = write_to_file(gpio_mode_fd[pin], buf, sizeof(buf));
         if ( ret <= 0 )
         {
             fprintf(stderr, "write gpio %d mode failed\n", pin);
             return -1;
         }
     }
     else
     {
         fprintf(stderr, "%s ERROR: invalid pin or mode, pin=%d, mode=%d\n",
             __FUNCTION__, pin, mode);
         return -1;
      }
      return 0;
}


int32_t GetBaud(int32_t baud) {
  return B9600;
}

int8_t GetDataBit(int8_t config) {
  return CS8;
}
int32_t GetStopbit(config) {
  return 1;
}
int8_t GetParity(config) {
  return 'N';
}
#define  SERIAL_8N1 1

int32_t InitUartTerm(SHDEVMANAGE_T *shdev) {
  int32_t ret;
  int32_t baud, rate;
  int8_t config = SERIAL_8N1;
  int8_t buff[80] = "Hello";
  int8_t rbuff[80];
  InitGPIO();
  hw_pinMode(GPIO0, IO_UART_FUNC);
  hw_pinMode(GPIO1, IO_UART_FUNC);
  ret = open(UARTNAME, O_RDWR| O_NOCTTY | O_NONBLOCK);
  if (ret < 0) {
	fprintf(stderr, "%s %d it is error: %d to fail to open uart.\n",
		__FILE__, __LINE__, errno);
	goto fail;
  }

  shdev->uart_fd = ret;
  tcgetattr(shdev->uart_fd, &shdev->orig_term);
  shdev->uart_term = shdev->orig_term;
  tcflush(shdev->uart_fd, TCIOFLUSH);
  baud = 9600;
  rate = GetBaud(baud);
  if (rate > 0) {
	cfsetispeed(&shdev->uart_term, rate);
	cfsetospeed(&shdev->uart_term, rate);
  } else {
	goto fail;
  }
  shdev->uart_term.c_cflag &= ~CSIZE;
  shdev->uart_term.c_cflag |= GetDataBit(config);
  switch (GetParity(config))
  {   
	case 'N':
	default:
	  shdev->uart_term.c_cflag &= ~PARENB;
	  shdev->uart_term.c_iflag &= ~INPCK;
	  break;
	case 'O':
	  shdev->uart_term.c_cflag |= (PARODD | PARENB);
	  shdev->uart_term.c_iflag |= INPCK;
	  break;  
	case 'E':
	  shdev->uart_term.c_cflag |= PARENB;
	  shdev->uart_term.c_cflag &= ~PARODD;
	  shdev->uart_term.c_iflag |= INPCK;
	  break;
  }  

  printf("%s %d\n", __FILE__, __LINE__);
  switch (GetStopbit(config))
  {   
	case 1:
	default:
	  shdev->uart_term.c_cflag &= ~CSTOPB;  
	  break;  
	case 2:
	  shdev->uart_term.c_cflag |= CSTOPB;  
	  break;
  }

  shdev->uart_term.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  ret = tcsetattr(shdev->uart_fd, TCSANOW, &shdev->uart_term);
  if (ret) {
	fprintf(stderr, "%s %d it is error: %d to set attr.\n",
		__FILE__, __LINE__, errno);
	goto fail;
  }
  tcflush(shdev->uart_fd, TCIOFLUSH);
  shdev->uart_state = 1;
  printf("%s %d\n", __FILE__, __LINE__);

struct timeval time;
int32_t len, fs_sel;
time.tv_sec = 10;
time.tv_usec = 0;
  write(shdev->uart_fd, buff, 5);
  FD_ZERO(&shdev->readfds);
  FD_SET(shdev->uart_fd, &shdev->readfds);
  fs_sel = select(shdev->uart_fd + 1, &shdev->readfds, NULL, NULL, &time);
  if (fs_sel) {
  read(shdev->uart_fd, rbuff, 80);
  rbuff[5] = '\0';
  printf("receive = %s\n", rbuff);
  }
	tcsetattr(shdev->uart_fd, TCSANOW, &shdev->orig_term);
	close(shdev->uart_fd);
  return ret;
fail:
  if (shdev->uart_fd) {
	close(shdev->uart_fd);
  }
  return ret;
}
int main()
{
  int32_t ret;

  InitUartTerm(&shdev_);

  // DeinitUartTerm(&shdev_);
fail:
  return ret;
}
